﻿
namespace Bildverarbeitung
{
    using System;
    using System.Collections.Generic;
    using System.Drawing;
    using System.Drawing.Imaging;

    using AForge.Imaging.Filters;
    using AForge.Imaging;
    using AForge;
    using AForge.Math.Geometry;

    public class HaasBastianDoorFilter : IFilter
    {
        private Bitmap image;
        //UnmanagedImage result;

        public String GetName()
        {
            return ("HaasBastian");
        }

        // private format translation dictionary
        private Dictionary<PixelFormat, PixelFormat> formatTranslations = new Dictionary<PixelFormat, PixelFormat>();

        public Dictionary<PixelFormat, PixelFormat> FormatTranslations
        {
            get { return formatTranslations; }
        }

        public HaasBastianDoorFilter()
        {
            formatTranslations[PixelFormat.Format8bppIndexed] = PixelFormat.Format8bppIndexed;
            formatTranslations[PixelFormat.Format24bppRgb] = PixelFormat.Format24bppRgb;
            formatTranslations[PixelFormat.Format32bppRgb] = PixelFormat.Format32bppRgb;
            formatTranslations[PixelFormat.Format32bppArgb] = PixelFormat.Format32bppArgb;

        }

        public Bitmap GetImageWithDoor(Bitmap images)
        {
            if (images == null)
            {
                System.Console.WriteLine("Kein Image gefunden!");
                return null;
            }
            else
            {
                this.image = images;
                Bitmap newResult = ProcessImage(image);
                return newResult;
            }
        }

        // Process image
        private Bitmap ProcessImage(Bitmap image)
        {
            Bitmap edgeImage = image;
            Grayscale f1 = new Grayscale(0.2125, 0.7154, 0.0721);
            edgeImage = f1.Apply(edgeImage);
            SobelEdgeDetector f2 = new SobelEdgeDetector();
            edgeImage = f2.Apply(edgeImage);

            //CannyEdgeDetector f2 = new CannyEdgeDetector(100,150);
            //edgeImage = f2.Apply(edgeImage);

            edgeImage = edgeImage.Clone(new Rectangle(0, 0, image.Width, image.Height), PixelFormat.Format24bppRgb);
            List<List<IntPoint>> edges = aforgeSampleCheck(edgeImage);

            Graphics g = Graphics.FromImage(image);
            Pen redPen = new Pen(Color.Red, 2);       // edge
            Pen greenPen = new Pen(Color.Green, 2);   // border
            SolidBrush yellowShape = new SolidBrush(Color.Yellow);

            float greatestRec = 0;
            List<IntPoint> greatestCorners = null;

            foreach (List<IntPoint> corners in edges)
            {
                //border draw
                g.DrawPolygon(greenPen, ToPointsArray(corners));

                //edges draw
                foreach (IntPoint point in corners)
                {
                    g.DrawRectangle(redPen, point.X - 1, point.Y - 1, 2, 2);
                }

                // if (corners.Count == 4) //nur vierecke
                if (checkGaußTrapez(corners) > greatestRec)
                {
                    greatestCorners = corners;
                    greatestRec = checkGaußTrapez(corners);

                }
            }


            g.FillPolygon(yellowShape, ToPointsArray(greatestCorners));


            redPen.Dispose();
            greenPen.Dispose();
            yellowShape.Dispose();
            g.Dispose();

            return image;
        }

        //GaußscheTrapezformel
        private float checkGaußTrapez(List<IntPoint> corners)
        {
            float fläche = 0;
            for (int i = 0; i < corners.Count; i++)
            {
                fläche = fläche + ((corners[i].X + corners[(i + 1) % corners.Count].X) * (corners[(i + 1) % corners.Count].Y + corners[i].Y));
            }
            fläche = fläche / 2;

            return fläche;
        }


        //Sample from AForge.net (SimpleShapeChecker)
        private List<List<IntPoint>> aforgeSampleCheck(Bitmap bitmap)
        {
            List<List<IntPoint>> edges = new List<List<IntPoint>>();

            // lock image
            BitmapData bitmapData = bitmap.LockBits(
                new Rectangle(0, 0, bitmap.Width, bitmap.Height),
                ImageLockMode.ReadWrite, bitmap.PixelFormat);

            // step 1 - turn background to black
            ColorFiltering colorFilter = new ColorFiltering();

            colorFilter.Red = new IntRange(0, 64);
            colorFilter.Green = new IntRange(0, 64);
            colorFilter.Blue = new IntRange(0, 64);
            colorFilter.FillOutsideRange = false;

            colorFilter.ApplyInPlace(bitmapData);

            // step 2 - locating objects
            BlobCounter blobCounter = new BlobCounter();

            blobCounter.FilterBlobs = true;
            blobCounter.MinHeight = 5;
            blobCounter.MinWidth = 5;

            blobCounter.ProcessImage(bitmapData);
            Blob[] blobs = blobCounter.GetObjectsInformation();
            bitmap.UnlockBits(bitmapData);

            // step 3 - check objects' type and highlight
            SimpleShapeChecker shapeChecker = new SimpleShapeChecker();



            for (int i = 0, n = blobs.Length; i < n; i++)
            {
                List<IntPoint> edgePoints = blobCounter.GetBlobsEdgePoints(blobs[i]);

                List<IntPoint> corners;

                // is triangle or quadrilateral
                if (shapeChecker.IsConvexPolygon(edgePoints, out corners))
                {
                    // get sub-type
                    PolygonSubType subType = shapeChecker.CheckPolygonSubType(corners);

                    if (subType != PolygonSubType.Unknown)
                    {
                        edges.Add(corners);
                    }

                }
            }

            return edges;
        }

        // Conver list of AForge.NET's points to array of .NET points
        private System.Drawing.Point[] ToPointsArray(List<IntPoint> points)
        {
            System.Drawing.Point[] array = new System.Drawing.Point[points.Count];

            for (int i = 0, n = points.Count; i < n; i++)
            {
                array[i] = new System.Drawing.Point(points[i].X, points[i].Y);
            }

            return array;
        }
    }
}

        


